package org.chen.client;

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.chen.common.exception.ServiceException;
import org.chen.config.HeyGenProperties;
import org.chen.domain.dto.TemplateDTO;
import org.chen.domain.dto.TemplateVariableResponse;
import org.chen.domain.entity.ApiKeyEntity;
import org.chen.domain.entity.BackgroundResource;
import org.chen.mapper.ApiKeyMapper;
import org.chen.request.VideoGenerateRequest;
import org.chen.response.*;
import org.chen.vo.QuotaVO;
import org.chen.vo.UserInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class HeyGenClient {
    @Autowired
    private HeyGenProperties heyGenProperties;

    @Autowired
    private OkHttpClient client;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ApiKeyMapper apiKeyMapper;  // 用于从数据库获取 API Key 和配额信息

    private static final String API_KEY_PREFIX = "apiKey:";
    
    public HeyGenClient() {
        this.client = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();
    }
    
    /**
     * 生成视频
     */
    public VideoGenerateResponse generateVideo(VideoGenerateRequest request) {
        try {
            String apiKey = getApiKey();
            MediaType mediaType = MediaType.parse("application/json");
//            log.info("request:{}", request);
            String requestBody = JSON.toJSONString(request);
            log.info("Request body: {}", requestBody);

            // 检查 URL 是否正确
            String apiUrl = heyGenProperties.getUrl() + "/video/generate";

            Request httpRequest = new Request.Builder()
                .url(apiUrl)
                .post(RequestBody.create(requestBody,mediaType))
                .addHeader("accept", "application/json")
                .addHeader("content-type", "application/json")
                .addHeader("x-api-key", apiKey)
                .build();

            try (Response response = client.newCall(httpRequest).execute()) {
//                log.error(response.toString());
                // 打印响应内容以便调试
                String responseBody = response.body() != null ? response.body().string() : null;

                if (!response.isSuccessful()) {
                    log.error("error:{}",response.toString());
                    throw new ServiceException("调用HeyGen API失败: " + response.code() + response.message());
                }

                if (responseBody == null || responseBody.isEmpty()) {
                    throw new ServiceException("API返回空响应");
                }

                VideoGenerateResponse videoGenerateResponse = JSON.parseObject(responseBody, VideoGenerateResponse.class);
                if (videoGenerateResponse == null) {
                    throw new ServiceException("无法解析API响应");
                }

                if (videoGenerateResponse.getData() == null) {
                    VideoGenerateResponse.Data data = new VideoGenerateResponse.Data();
                    data.setUnTask(false);
                    videoGenerateResponse.setData(data);
                }

                videoGenerateResponse.getData().setApi_key(apiKey);
                return videoGenerateResponse;
            }
        } catch (Exception e) {
            log.error("Generate video failed", e);
            throw new ServiceException("生成视频失败: " + e.getMessage());
        }
    }

    /**
     * 删除视频
     */
    public void deleteRemoteVideo(String videoId, String apiKey) {
        Request request = new Request.Builder()
                .url(heyGenProperties.getDeleteUrl() + videoId)
                .delete(null)
                .addHeader("accept", "application/json")
                .addHeader("x-api-key", apiKey)
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {

            }
        }catch (Exception e) {
            log.error("Delete remote video failed", e);
        }
    }

    /**
     * 获取所有虚拟人物
     */
    public AvatarResponse getAvatars() {
        try {
            String apiKey = getApiKey();
            Request request = new Request.Builder()
                    .url(heyGenProperties.getUrl() + "/avatars")
                    .get()
                    .addHeader("accept", "application/json")
                    .addHeader("x-api-key", apiKey)
                    .build();

            try (Response response = client.newCall(request).execute()) {
                String responseBody = response.body() != null ? response.body().string() : null;
                if (!response.isSuccessful()) {
                    throw new ServiceException("调用获取虚拟人物API失败: " + response.code());
                }
                return JSON.parseObject(responseBody, AvatarResponse.class);
            }
        } catch (Exception e) {
            log.error("Get avatars failed", e);
            throw new ServiceException("获取虚拟人物列表失败: " + e.getMessage());
        }
    }

    /**
     * 获取所有语音
     */
    public VoiceResponse getVoices() {
        try {
            String apiKey = getApiKey();
            Request request = new Request.Builder()
                    .url(heyGenProperties.getUrl() + "/voices")
                    .get()
                    .addHeader("accept", "application/json")
                    .addHeader("x-api-key", apiKey)
                    .build();

            try (Response response = client.newCall(request).execute()) {
                String responseBody = response.body() != null ? response.body().string() : null;
                if (!response.isSuccessful()) {
                    throw new ServiceException("调用获取语音API失败: " + response.code());
                }

                return JSON.parseObject(responseBody, VoiceResponse.class);
            }
        } catch (Exception e) {
            log.error("Get voices failed", e);
            throw new ServiceException("获取语音列表失败: " + e.getMessage());
        }
    }

    /**
     * 获取视频状态
     * @param videoId 视频id
     * @return 状态信息
     */
    public VideoStatusResponse getVideoStatus(String videoId, String apiKey) {
        try {
            Request request = new Request.Builder()
                    .url(heyGenProperties.getV1Url() + "/video_status.get?video_id=" + videoId)
                    .get()
                    .addHeader("accept", "application/json")
                    .addHeader("x-api-key", apiKey)
                    .build();

            try (Response response = client.newCall(request).execute()) {
                String responseBody = response.body() != null ? response.body().string() : null;
//                log.info("Get video status response: {}", responseBody);
                if (!response.isSuccessful()) {
                    throw new ServiceException("调用HeyGen API获取视频状态失败: " + response.code());
                }

                return JSON.parseObject(responseBody, VideoStatusResponse.class);
            }
        } catch (Exception e) {
            log.error("Get video status failed", e);
            throw new ServiceException("获取视频状态失败: " + e.getMessage());
        }
    }

    /**
     * 获取API配额信息
     */
    public QuotaVO getQuota(String apiKey) {
        Request request = new Request.Builder()
                .url(heyGenProperties.getUserUrl())
                .get()
                .addHeader("accept", "application/json")
                .addHeader("x-api-key", apiKey)
                .build();

        try (Response userResponse = client.newCall(request).execute()) {
            String responseBody = userResponse.body() != null ? userResponse.body().string() : null;
            return JSON.parseObject(responseBody, QuotaVO.class);
        }catch (Exception e) {
            throw new ServiceException("获取配额失败", e);
        }
    }

    /**
     * 获取API用户信息
     */
    public UserInfoVO getUserInfo(String apiKey) {
        Request request = new Request.Builder()
                .url(heyGenProperties.getV1UserUrl())
                .get()
                .addHeader("accept", "application/json")
                .addHeader("x-api-key", apiKey)
                .build();

        try (Response response = client.newCall(request).execute()){
            String responseBody = response.body() != null ? response.body().string() : null;
            return JSON.parseObject(responseBody, UserInfoVO.class);
        } catch (IOException e) {
            log.error("获取用户信息失败", e);
            throw new ServiceException("获取用户信息失败");
        }
    }

    /**
     * 获取有效的 API Key，带配额验证和重试机制
     */
    public String getApiKey() {
        // 重试计数器
        int retryCount = 0;
        int maxRetry = 3;

        while (retryCount < maxRetry) {
            try {
                // 先从缓存中获取 API Key 列表
                List<String> apiKeys = redisTemplate.opsForList().range("apiKeys", 0, -1);  // 获取所有缓存中的 API Key

                if (apiKeys == null || apiKeys.isEmpty()) {
                    // 如果缓存没有 API Key，从数据库加载并缓存
                    loadApiKeysToRedis();
                    apiKeys = redisTemplate.opsForList().range("apiKeys", 0, -1);

                    // 如果仍然为空，说明数据库中没有可用的API Key
                    if (apiKeys == null || apiKeys.isEmpty()) {
                        throw new ServiceException("没有可用的API Key");
                    }
                }

                // 随机选择一个 API Key
                Random random = new Random();
                String selectedApiKey = apiKeys.get(random.nextInt(apiKeys.size()));

                // 验证API Key是否有效
                QuotaVO quota = getQuota(selectedApiKey);

                if (quota != null && quota.getData() != null && quota.getData().getRemaining_quota() > 0) {
                    return selectedApiKey;
                } else {
                    // 如果配额不足，将此键从列表中移除
                    redisTemplate.opsForList().remove("apiKeys", 1, selectedApiKey);
                    // 更新配额信息
                    updateApiKeyQuota(selectedApiKey);
                    retryCount++;
                }
            } catch (Exception e) {
                log.error("Get API Key failed, retry count: {}", retryCount, e);
                retryCount++;
                // 如果异常是由于Redis连接问题，可以添加短暂休眠
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        }

        // 超过最大重试次数，抛出异常
        throw new ServiceException("无法获取有效的API Key，请检查API Key配置");
    }

    /**
     * 从数据库加载 API Key 和配额信息到 Redis
     */
    private void loadApiKeysToRedis() {
        List<ApiKeyEntity> apiKeyInfoList = apiKeyMapper.selectList(null);  // 假设从数据库获取 API Key 信息

        // 将 API Key 信息缓存到 Redis
        for (ApiKeyEntity info : apiKeyInfoList) {
            String apiKey = info.getApiKey();
            redisTemplate.opsForList().leftPush("apiKeys", apiKey);
            redisTemplate.opsForValue().set(API_KEY_PREFIX + apiKey + ":quota", String.valueOf(info.getRemainingQuota()), 1, TimeUnit.DAYS);  // 设置配额缓存，有效期为一天
        }
    }

    /**
     * 更新某个 API Key 的配额
     */
    private void updateApiKeyQuota(String apiKey) {
        String quota = redisTemplate.opsForValue().get(API_KEY_PREFIX + apiKey + ":quota");

        if (quota != null && Integer.parseInt(quota) > 0) {
            // 调用 API 更新配额
            QuotaVO response = getQuota(apiKey);
            if (response.getData().getRemaining_quota() > 0) {
                // 更新缓存中的配额
                redisTemplate.opsForValue().set(API_KEY_PREFIX + apiKey + ":quota", String.valueOf(response.getData().getRemaining_quota()), 1, TimeUnit.DAYS);
            }
        }
    }

    /**
     * 获取与key有关的虚拟人物组
     */
    public KeyAvatarGroupResponse getKeyAvatarGroup() {
        try {
            String apiKey = getApiKey();
            Request request = new Request.Builder()
                    .url("https://api.heygen.com/v2/avatar_group.list?include_public=false")
                    .get()
                    .addHeader("accept", "application/json")
                    .addHeader("x-api-key", apiKey)
                    .build();

            try (Response response = client.newCall(request).execute()) {
                String responseBody = response.body() != null ? response.body().string() : null;
                if (!response.isSuccessful()) {
                    throw new ServiceException("调用获取Key虚拟人物组API失败: " + response.code());
                }

                return JSON.parseObject(responseBody, KeyAvatarGroupResponse.class);
            }
        } catch (Exception e) {
            log.error("Get avatars failed", e);
            throw new ServiceException("获取Key虚拟人物组失败: " + e.getMessage());
        }
    }

    /**
     * 获取key自定义的人物角色
     */
    public KeyAvatarResponse getKeyAvatar(String avatarId) {
        try {
            String apiKey = getApiKey();
            Request request = new Request.Builder()
                    .url("https://api.heygen.com/v2/avatar_group/" + avatarId +"/avatars")
                    .get()
                    .addHeader("accept", "application/json")
                    .addHeader("x-api-key", apiKey)
                    .build();

            try (Response response = client.newCall(request).execute()) {
                String responseBody = response.body() != null ? response.body().string() : null;
                if (!response.isSuccessful()) {
                    throw new ServiceException("调用获取key自定义的人物角色API失败: " + response.code());
                }

                return JSON.parseObject(responseBody, KeyAvatarResponse.class);
            }
        } catch (Exception e) {
            log.error("Get avatars failed", e);
            throw new ServiceException("获取key自定义的人物角色失败: " + e.getMessage());
        }
    }

    /**
     * 获取模板列表
     */
    public List<TemplateDTO> listTemplates() throws IOException {
        String apiKey = getApiKey();
        Request request = new Request.Builder()
                .url("https://api.heygen.com/v2/templates")
                .get()
                .addHeader("accept", "application/json")
                .addHeader("x-api-key", apiKey)
                .build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful() || response.body() == null) {
            throw new IOException("Failed to get templates");
        }

        String responseBody = response.body().string();
        JsonNode root = objectMapper.readTree(responseBody);
        if (root.has("error") && !root.get("error").isNull()) {
            throw new IOException("API error: " + root.get("error").asText());
        }

        JsonNode templates = root.get("data").get("templates");
        return objectMapper.convertValue(templates,
                new TypeReference<List<TemplateDTO>>() {});
    }

    /**
     * 获取模板变量
     */
    public TemplateVariableResponse getTemplateVariables(String templateId) throws IOException {
        String apiKey = getApiKey();
        Request request = new Request.Builder()
                .url("https://api.heygen.com/v2/template/" + templateId)
                .get()
                .addHeader("accept", "application/json")
                .addHeader("x-api-key", apiKey)
                .build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful() || response.body() == null) {
            throw new IOException("Failed to get template variables");
        }

        String responseBody = response.body().string();
        JsonNode root = objectMapper.readTree(responseBody);
        if (root.has("error") && !root.get("error").isNull()) {
            throw new IOException("API error: " + root.get("error").asText());
        }

        JsonNode data = root.get("data");
        return objectMapper.convertValue(data, TemplateVariableResponse.class);
    }

    /**
     * 生成模板视频
     */
    public String generateVideo(String templateId, Map<String, Object> requestParams) throws IOException {
        String apiKey = getApiKey();
        String requestJson = objectMapper.writeValueAsString(requestParams);

        // 发送请求
        Request request = new Request.Builder()
                .url("https://api.heygen.com/v2/template/" + templateId + "/generate")
                .post(RequestBody.create(
                        MediaType.parse("application/json"),
                        requestJson
                ))
                .addHeader("accept", "application/json")
                .addHeader("content-type", "application/json")
                .addHeader("x-api-key", apiKey)
                .build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful() || response.body() == null) {
            throw new IOException("Failed to generate video: " + response.code());
        }

        String responseBody = response.body().string();
        JsonNode root = objectMapper.readTree(responseBody);

        if (root.has("error") && !root.get("error").isNull()) {
            throw new IOException("API error: " + root.get("error").asText());
        }

        JsonNode data = root.get("data");
        return data.get("video_id").asText();
    }

    /**
     * 查询视频状态
     */
    public VideoTemplateStatusResponse checkVideoStatus(String videoId) throws IOException {
        String apiKey = getApiKey();
        Request request = new Request.Builder()
                .url("https://api.heygen.com/v2/video/" + videoId)
                .get()
                .addHeader("accept", "application/json")
                .addHeader("x-api-key", apiKey)
                .build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful() || response.body() == null) {
            throw new IOException("Failed to check video status");
        }

        String responseBody = response.body().string();
        JsonNode root = objectMapper.readTree(responseBody);
        if (root.has("error") && !root.get("error").isNull()) {
            throw new IOException("API error: " + root.get("error").asText());
        }

        JsonNode data = root.get("data");
        VideoTemplateStatusResponse result = new VideoTemplateStatusResponse();
        result.setStatus(data.has("status") ? data.get("status").asText() : "processing");

        if (data.has("video_url")) {
            result.setVideoUrl((data.get("video_url").asText()));
        }

        if (data.has("error")) {
            result.setErrorMessage(data.get("error").asText());
        }

        return result;
    }
}